package org.scratchcrew.web.upload;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.cometd.Bayeux;
import org.cometd.Channel;
import org.scratchcrew.domain.ScratchFile;
import org.scratchcrew.services.ScratchFileService;
import org.scratchcrew.web.cometd.handlers.BoardChannelSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import eu.medsea.mimeutil.MimeType;
import eu.medsea.mimeutil.MimeUtil;
import eu.medsea.mimeutil.detector.MagicMimeMimeDetector;

@Component(value = "upload")
public class UploadHandler implements HttpRequestHandler, ServletContextAware {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private ScratchFileService scratchFileService;
	@Autowired
	private Bayeux bayeux;
	@Autowired
	private BoardChannelSupport boardChannelSupport;
	private ServletContext servletContext;

	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;

	}

	@PostConstruct
	public void init() {
		MimeUtil.addMimeDetector(new MagicMimeMimeDetector());
	}

	@Override
	public void handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		if (!(request instanceof MultipartHttpServletRequest)) {
			logger.warn("Not multipart request passed to");
			return;
		}
		MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
		doHandleRequest(multipartHttpServletRequest, response);
	}

	@SuppressWarnings("unchecked")
	protected void doHandleRequest(MultipartHttpServletRequest request,
			HttpServletResponse response) throws IOException {
		logger.trace("parm map: " + request.getParameterMap().toString());
		String boardIdString = request.getParameter("boardId");

		Long boardId;
		if (boardIdString != null) {
			try {
				boardId = Long.valueOf(boardIdString);
			} catch (NumberFormatException e) {
				boardId = null;
			}
		} else {
			boardId = null;
		}
		if (logger.isTraceEnabled()) {
			logger.trace("file map: " + request.getFileMap().toString());
		}

		Collection<MultipartFile> multipartFiles = request.getFileMap()
				.values();
		for (MultipartFile multipartFile : multipartFiles) {

			// FIXME: this may contain client file system path.
			String fileName = multipartFile.getOriginalFilename();
			byte[] file = multipartFile.getBytes();
			Collection mimeTypes = MimeUtil.getMimeTypes(file);
			Iterator<MimeType> mimeTypesIterator = mimeTypes.iterator();
			MimeType mimeType = null;
			while (mimeTypesIterator.hasNext()) {
				mimeType = mimeTypesIterator.next();
				if ("image".equals(mimeType.getMediaType())) {
					break;
				}
			}
			if (mimeType == null) {
				mimeType = (MimeType) mimeTypes.iterator().next();
			}

			if (logger.isDebugEnabled()) {
				logger.debug("Saving new file.");
			}

			ScratchFile scratchFile = scratchFileService.create(boardId,
					fileName, mimeType.toString(), file);
			// FIXME: fix this hard coded values
			Integer x = 0;
			Integer y = 0;
			Integer width = 450;
			Integer height = 200;
			String srcUrl = String.format("%s/file?id=%d", 
					servletContext.getContextPath(), scratchFile
					.getId());

			Map<String, Object> shape = new HashMap<String, Object>();
			shape.put("type", "image");
			shape.put("x", x);
			shape.put("y", y);
			shape.put("width", width);
			shape.put("height", height);
			shape.put("src", srcUrl);
			
			Map<String, Object> staticData = new HashMap<String, Object>();
			staticData.put("shape", shape);
			
			Map<String, Object> scratchData = new HashMap<String, Object>();
			
			Map<String, Object> content = new HashMap<String, Object>();
			content.put("staticData", staticData);
			content.put("scratchData", scratchData);

			Map<String, Object> scratchMessage = new HashMap<String, Object>();
			scratchMessage.put("type", "createScratch");
			scratchMessage.put("content", content);
			String channel = boardChannelSupport.getChannelByBoardId(boardId);
			Channel boardChannel = bayeux.getChannel(channel, false);
			if (boardChannel != null) {
				// XXX: This can be before saving the file
				boardChannel.publish(null, scratchMessage, null);
			}
		}
	}
}
